package cn.csg.ams.collect2.poptopics.redisPool;

import cn.csg.ams.collect2.poptopics.datahub.TupleRecordDataUtils;
import cn.csg.ams.collect2.poptopics.entity.RecordInfo;
import cn.csg.ams.collect2.poptopics.infrastructure.utils.JsonUtil;
import com.aliyun.datahub.client.model.TupleRecordData;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 告警池
 * 按台区编号为大key，运行电能表标识为小key，以台区维度存储终端与电能表的停电告警，用于停电研判
 * 告警池中的台区只会是已改造的公变台区，只有已改造的公变台区，才会使用告警池中的数据进行研判
 */
@Component
public class AlarmPool {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 台区告警信息key
     */
    public static final String TA_ALARM_KEY = "ta_alarm_";


    // @PostConstruct
    public void test() throws Exception {
        ValueOperations<String, String> operations = redisTemplate.opsForValue();
        operations.set("test666", "123");
        String a = operations.get("test666");
        System.out.println("操作reids成功");
    }


    /**
     * 获取key
     */
    private String getKey(String taNo, String areaCode) {
        return TA_ALARM_KEY + areaCode + "_" + taNo;
    }


    /**
     * 获取告警对象
     */
    private String getValue(TupleRecordData data, RecordInfo recordInfo) {
        // 运行终端标识
        String runTermId = TupleRecordDataUtils.getStringField(data, 1);
        // 终端类型
        String termType = recordInfo.getTermType();
        // 运行电能表标识
        String runMeterId = TupleRecordDataUtils.getStringField(data, 2);
        // 告警来源，代码分类：GJLY=|{1终端；2电表；3主站}
        String alarmSourCode = TupleRecordDataUtils.getStringField(data, 11);
        // 测量点号
        Long longField = TupleRecordDataUtils.getLongField(data, 3);

        // 告警时间
        String alarmTime = TupleRecordDataUtils.getStringField(data, 23);

        AlarmInfo alarmInfo = new AlarmInfo();
        // 运行终端标识
        alarmInfo.setRunTermId(runTermId);
        // 终端类型
        alarmInfo.setTermType(termType);
        alarmInfo.setOutageType("1".equals(alarmSourCode) ? "1" : "3");
        // 终端告警、测量点号在[1600- 1611]范围内的告警为分支告警 - 045
        if ("1".equals(termType) && longField != null && longField >= 1600 && longField <= 1611) {
            alarmInfo.setTermType("045");
            alarmInfo.setOutageType("2");
        }
        alarmInfo.setRunMeterId(runMeterId);
        alarmInfo.setAlarmSourCode(alarmSourCode);
        alarmInfo.setAlarmTime(alarmTime);
        alarmInfo.setTaType(recordInfo.getTaType());
        // 所属分路编号
        alarmInfo.setShuntNo(recordInfo.getBranchNo());
        // 数据时间
        alarmInfo.setDataTime(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
        return JsonUtil.toJson(alarmInfo);
    }


    /**
     * 从redis中获取告警信息
     *
     * @param taNo       台区编号
     * @param runMeterId 运行电能表标识
     */
    public AlarmInfo getTaAlarm(String taNo, String runMeterId, String areaCode) {
        String key = getKey(taNo, areaCode);
        Object o = redisTemplate.opsForHash().get(key, runMeterId);
        if (o == null) {
            return null;
        }
        return JsonUtil.toObject(o.toString(), AlarmInfo.class);
    }


    /**
     * 将告警信息添加到告警池中
     *
     * @param data       告警数据
     * @param recordInfo 档案信息
     */
    public void addAlarmToPool(TupleRecordData data, RecordInfo recordInfo, String areaCode) {
        // key
        String key = getKey(recordInfo.getTaNo(), areaCode);
        // 运行电能表标识为hashKey
        Object hashKey = recordInfo.getRunMeterId();
        // 告警信息为value
        String value = getValue(data, recordInfo);
        // 设置该台区的key过期时间为3分钟 (只能设置整个大key的过期时间, 不能为每个小key单独设置过期时间)
        redisTemplate.expire(key, 7, TimeUnit.DAYS);

        // 添加到告警池中
        redisTemplate.opsForHash().put(key, hashKey, value);
    }


    /**
     * 修改redis中的告警信息（已研判为部分停电）
     *
     * @param taNo     台区编号
     * @param areaCode 地区编码
     * @param partUser 部分停电用户在redis中的信息
     */
    public void updateAlarm(String taNo, String areaCode, List<AlarmInfo> partUser) {
        // key
        String key = getKey(taNo, areaCode);
        for (AlarmInfo alarmInfo : partUser) {
            // 运行电能表标识
            String hashKey = alarmInfo.getRunMeterId();
            // 修改已判为部分停电的状态
            alarmInfo.setIsTdUser("1");
            // 更新告警池中信息
            redisTemplate.opsForHash().put(key, hashKey, JsonUtil.toJson(alarmInfo));
        }
    }


    /**
     * 获取台区下的所有告警信息
     *
     * @param taNo     台区编号
     * @param areaCode 地区编码
     */
    public List<AlarmInfo> getAlarmByTaNo(String taNo, String areaCode) {
        // key
        String key = getKey(taNo, areaCode);
        // 获取台区下所有告警信息
        Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);

        // 解析对象
        List<AlarmInfo> alarmList = new ArrayList<>();
        for (Map.Entry<Object, Object> entry : entries.entrySet()) {
            Object value = entry.getValue();
            if (value == null) {
                continue;
            }
            AlarmInfo alarmInfo = JsonUtil.toObject(value.toString(), AlarmInfo.class);
            alarmList.add(alarmInfo);
        }
        return alarmList;
    }


    /**
     * 删除台区下所有告警信息
     *
     * @param taNo     台区编号
     * @param areaCode 地区编码
     */
    public void deleteTaAlarmInfo(String taNo, String areaCode) {
        String key = getKey(taNo, areaCode);
        redisTemplate.delete(key);
    }


    /**
     * 删除台区下单个电表的告警信息
     *
     * @param taNo       台区编号
     * @param runMeterId 运行电能表标识
     * @param areaCode   地区编码
     */
    public void deleteTaAlarmInfo(String taNo, String runMeterId, String areaCode) {
        String key = getKey(taNo, areaCode);
        redisTemplate.opsForHash().delete(key, runMeterId);
    }

    /**
     * 删除台区下多个电表的告警信息
     *
     * @param taNo        台区编号
     * @param runMeterIds 运行电能表标识
     * @param areaCode    地区编码
     */
    public void deleteTaAlarmInfo(String taNo, List<String> runMeterIds, String areaCode) {
        for (String runMeterId : runMeterIds) {
            deleteTaAlarmInfo(taNo, runMeterId, areaCode);
        }
    }


    /**
     * 告警池中的数据实体
     */
    @Data
    public static class AlarmInfo {

        /**
         * 运行终端标识
         */
        public String runTermId;

        /**
         * 运行终端类型( 03.负荷终端、 04.配变终端、 05.集中器、 054.分支)
         */
        public String termType;

        /**
         * 运行电表标识
         */
        public String runMeterId;

        /**
         * 告警来源 {1终端、2电表}
         */
        public String alarmSourCode;

        /**
         * 告警时间
         */
        private String alarmTime;

        /**
         * 数据时间
         */
        private String dataTime;

        /**
         * 台区编号
         */
        private String taNo;

        // 1 公变  2专变
        private String taType;

        /**
         * 分路编号
         */
        private String shuntNo;

        /**
         * 分路下所属低压用户数
         */
        private Integer shuntCustCnt;

        // 1 表示为台区总表相关的告警信息   智能量测终端   配变终端  集中器  负荷终端   2表示为分支相关的告警信息  以电表告警的信息传递上来      3表示为电表 用户相关告警信息
        private String outageType;

        /**
         * 是否已被判为部分用户停电(1-是)
         * 已被判为部分用户停电的，不在参与部分用户停电的累计研判
         */
        private String isTdUser;
    }

}
